<?php


namespace common\service;


use common\exception\LogicException;
use common\model\ChatModel;
use common\model\ChatUserModel;
use common\model\DepartmentModel;
use common\model\MediaModel;
use common\model\RoleModel;
use common\model\TenantUserDepartmentModel;
use common\model\TenantUserModel;
use common\model\TenantUserRoleModel;
use common\model\UserModel;
use support\ErrorCode;
use support\SingletonTrait;
use think\Cache;

class TenantUserService
{
    use SingletonTrait;

    /**
     * 查询租户用户
     * @param $param
     * @param bool $includeEmployed
     * @return array
     */
    public function selectTenantUser($param, bool $includeEmployed)
    {
        $res = [
            'total' => 0,
            'rows' => [],
        ];
        $page = $param['page'] ?? [1, C('database.database_max_select_rows')];
        $order = $param['order'] ?? 'tenant_user.id DESC';
        $filter = $param['filter'] ?? [];
        if (!$includeEmployed) {
            $filter['tenant_user.status'] = ['NEQ', TenantUserModel::STATUS_UNEMPLOYED];
        }
        $fields = [
            'user.id',
            'user.name',
            'user.phone',
            'user.email',
            'tenant_user.id',
            'tenant_user.user_id',
            'tenant_user.tenant_position_id',
            'tenant_position.id',
            'tenant_position.name',
        ];

        $res['total'] = model(TenantUserModel::class)
            ->join("user ON user.id = tenant_user.user_id")
            ->join('tenant_user_department on tenant_user_department.tenant_user_id = tenant_user.id', 'LEFT')
            ->join('tenant_user_role on tenant_user_role.tenant_user_id = tenant_user.id', 'LEFT')
            ->join("department ON tenant_user_department.department_id = department.id")
            ->join('role ON role.id = tenant_user_role.role_id')
            ->join('tenant_position on tenant_user.tenant_position_id = tenant_position.id', 'LEFT')
            ->where($filter)
            ->count();

        if ($res['total'] == 0) {
            return $res;
        }
        $res['rows'] = model(TenantUserModel::class)
            ->join("user ON user.id = tenant_user.user_id")
            ->join('tenant_user_department on tenant_user_department.tenant_user_id = tenant_user.id', 'LEFT')
            ->join('tenant_user_role on tenant_user_role.tenant_user_id = tenant_user.id', 'LEFT')
            ->join("department ON tenant_user_department.department_id = department.id")
            ->join('role ON role.id = tenant_user_role.role_id')
            ->join('tenant_position on tenant_user.tenant_position_id = tenant_position.id', 'LEFT')
            ->where($filter)
            ->field(build_complex_query_fields($fields, '__'))
            ->page($page[0], $page[1])
            ->order($order)
            ->group('tenant_user.id')
            ->select();
        if (empty($res['rows'])) {
            return $res;
        }
        $tenantUserIdList = array_column($res['rows'], 'tenant_user__id');
        $userIdList = array_column($res['rows'], 'user__id');
        $avatars = model(MediaModel::class)->where(['module' => 'user', 'type' => 'thumb', 'link_id' => ['IN', implode(',', $userIdList)]])->select();
        $avatarsMap = array_column($avatars, null, 'link_id');

        $userDepartmentRoleInfoList = $this->getTenantUserListDepartmentRole($tenantUserIdList);
        foreach ($avatarsMap as &$avatar) {
            $avatar = CommonService::getFormatAttrData(model(MediaModel::class), $avatar);
        }
        foreach ($res['rows'] as &$row) {
            $row = separate_complex_query_data($row);
            $row['user_avatar'] = $avatarsMap[$row['user']['id']] ?? null;
            $row['department_info'] = $row['role_info'] = [];
            if (isset($userDepartmentRoleInfoList[$row['tenant_user']['id']])) {
                $row = array_merge($row, $userDepartmentRoleInfoList[$row['tenant_user']['id']]);
            }
        }
        return $res;
    }

    /**
     * 公司成员数据
     * @param int $tenantId
     * @param bool $includeEmployed
     * @return array
     */
    public function tree(int $tenantId, bool $includeEmployed)
    {
        $qf = [
            'user.id',
            'user.name',
            'tenant_user.id',
            'tenant_user.user_id',
            'tenant_user.status',
        ];
        $filter = [
            'tenant_user.tenant_id' => $tenantId,
            'user.is_system' => UserModel::IS_SYSTEM_NO,
            'user.active' => 1, // 过滤激活状态，此状态独立于 租户部门成员的离职状态
            'user.status' => UserModel::STATUS_ENABLE
        ];
        if (!$includeEmployed) {
            $filter['tenant_user.status'] = ['NEQ', TenantUserModel::STATUS_UNEMPLOYED];
        }
        $tenantUserList = model(TenantUserModel::class)
            ->join('user on user.id = tenant_user.user_id')
            ->where($filter)
            ->field(build_complex_query_fields($qf, '__'))
            ->select();

        $userIdList = [];
        $tenantUserIdList = [];
        foreach ($tenantUserList as &$tenantUser) {
            $tenantUser = separate_complex_query_data($tenantUser, '__');
            $userIdList[$tenantUser['user']['id']] = $tenantUser['user']['id'];
            $tenantUserIdList[] = $tenantUser['tenant_user']['id'];
        }
        $tenantUserRoleDepartmentInfoList = $this->getTenantUserListDepartmentRole($tenantUserIdList);

        $avatars = model(MediaModel::class)
            ->where(['module' => 'user', 'type' => 'thumb', 'link_id' => ['IN', implode(',', $userIdList)]])
            ->field('link_id,thumb')
            ->select();
        $avatarsMap = array_column($avatars, 'thumb', 'link_id');
        unset($tenantUser);

        $departmentList = [];
        $departmentIdList = [];
        $departmentIdIndex = 0;
        foreach ($tenantUserList as $tenantUserListIndex => &$tenantUser) {
            $tenantUserId = $tenantUser['tenant_user']['id'];
            $userId = $tenantUser['user']['id'];
            $tenantUser['user']['avatar'] = $avatarsMap[$userId] ?? null;
            $tenantUser['role_info'] = [];
            if (!isset($tenantUserRoleDepartmentInfoList[$tenantUserId])) {
                continue;
            }
            $tenantUserList[$tenantUserListIndex]['role_info'] = $tenantUserRoleDepartmentInfoList[$tenantUserId]['role_info'];
            foreach ($tenantUserRoleDepartmentInfoList[$tenantUserId]['department_info'] as $department) {
                if (!array_key_exists($department['id'], $departmentIdList)) {
                    $departmentList[] = $department;
                    $departmentIdList[$department['id']] = $departmentIdIndex;
                    $departmentIdIndex += 1;
                }
                $departmentList[$departmentIdList[$department['id']]]['children'][] = &$tenantUserList[$tenantUserListIndex];
            }
        }
        return $departmentList;
    }

    /**
     * 设置角色
     * @param $data
     * @return array
     * @throws \Throwable
     */
    public function setRoles($data)
    {
        //查找用户是否已经加入本租户
        $tenantUserModel = model(TenantUserModel::class);
        $existUser = $tenantUserModel->where(['user_id' => $data['user_id'], 'tenant_id' => $data['tenant_id']])->find();
        if (empty($existUser)) {
            $existUser = $tenantUserModel->addItem(['tenant_id' => $data['tenant_id'], 'user_id' => $data['user_id'], 'status' => 'invalid']);
        }
        if (!empty($data['role_id'])) {
            $roles = model(RoleModel::class)->where(['id' => ['IN', $data['role_id']]])->select();
            if (empty($roles)) {
                // 传递的role id 不合法
                return [];
            }
            $data['role_id'] = array_column($roles, 'id');
        }

        $existRoles = model(TenantUserRoleModel::class)->where(['tenant_user_id' => $existUser['id']])->select();
        $existRoleIdList = array_column($existRoles, 'role_id');
        $needDeleteTenantUserRoleMap = array_column($existRoles, 'id', 'role_id');
        $tenantUserRoleList = [];
        foreach ($data['role_id'] as $roleId) {
            if (in_array($roleId, $existRoleIdList)) {
                unset($needDeleteTenantUserRoleMap[$roleId]);
                continue;
            }
            $tenantUserRoleList[] = [
                'tenant_user_id' => $existUser['id'],
                'role_id' => $roleId,
                'created' => time(),
                'created_by' => fill_created_by(),
            ];
        }
        // 校验是否为最后一个租户管理员，一个团队至少一个租户管理员
        $this->checkIsLastTenantAdmin($data['tenant_id'], $needDeleteTenantUserRoleMap);
        $resData = [];
        model(TenantUserRoleModel::class)->startTrans();
        try {
            if (!empty($tenantUserRoleList)) {
                $resData['added'] = model(TenantUserRoleModel::class)->addAll($tenantUserRoleList);
            }
            if (!empty($needDeleteTenantUserRoleMap)) {
                $resData['delete'] = model(TenantUserRoleModel::class)->where(['id' => ['IN', array_values($needDeleteTenantUserRoleMap)]])->delete();
            }
            model(TenantUserRoleModel::class)->commit();
        } catch (\Throwable $e) {
            model(TenantUserRoleModel::class)->rollback();
            throw $e;
        }

        Cache::rm('tenant_user_tree' . $data['tenant_id']);
        return $resData;
    }

    /**
     * 校验是否为最后一个租户管理员，一个团队至少一个租户管理员
     * @param $tenantId [租户id]
     * @param $needDeleteTenantUserRoleMap [需要删除的租户用户和角色map]
     */
    private function checkIsLastTenantAdmin($tenantId, $needDeleteTenantUserRoleMap)
    {
        $tenantAdmin = model(RoleModel::class)->where(['code' => RoleModel::TENANT_ADMINISTRATOR_CODE])->field('id')->find();
        if (empty($tenantAdmin['id'])) {
            throw_strack_exception('Tenant administrator not found', ErrorCode::ROLE_NOT_FOUND);
        }
        // 如果删除角色为租户管理员，需要判断团队是否只有一个租户管理员
        if (isset($needDeleteTenantUserRoleMap[$tenantAdmin['id']]) && $this->getTenantAdminTotal($tenantId, $tenantAdmin['id']) <= 1) {
            throw_strack_exception('Tenant has at least one tenant administrator', ErrorCode::TENANT_HAS_AT_LEAST_ONE_ADMIN);
        }
    }

    /**
     * 统计团队租户管理员人员数
     * @param $tenantId [租户id]
     * @param $tenantAdminId [租户管理员id]
     * @return object|\think\Model|\think\model\RelationModel
     */
    public function getTenantAdminTotal($tenantId, $tenantAdminId)
    {
        return model(TenantUserModel::class)
            ->join("tenant_user_role ON tenant_user.id = tenant_user_role.tenant_user_id")
            ->where(['tenant_user.tenant_id' => $tenantId, 'tenant_user_role.role_id' => $tenantAdminId])
            ->count();
    }

    /**
     * 设置部门
     * @param $param
     * @return array
     * @throws \Throwable
     */
    public function setDepartments($param)
    {
        //查找用户是否已经加入本租户
        $tenantUserModel = model(TenantUserModel::class);
        $existUser = $tenantUserModel->where(['user_id' => $param['user_id'], 'tenant_id' => $param['tenant_id']])->find();
        if (empty($existUser)) {
            $existUser = $tenantUserModel->addItem(['tenant_id' => $param['tenant_id'], 'user_id' => $param['user_id'], 'status' => 'invalid']);
        }
        if (!empty($param['department_id'])) {
            $tenantDepartmentList = model(DepartmentModel::class)->where(['tenant_id' => $param['tenant_id'], 'id' => ['IN', implode(',', $param['department_id'])]])->select();
            if (empty($tenantDepartmentList)) {
                // 传递的部门id不合法
                return [];
            }
            $param['department_id'] = array_column($tenantDepartmentList, 'id');
        }
        $existDepartments = model(TenantUserDepartmentModel::class)->where(['tenant_user_id' => $existUser['id']])->select();
        $needDeleteTenantUserDepartmentIdList = array_column($existDepartments, 'id', 'department_id');
        $existDepartmentIdList = array_column($existDepartments, 'department_id');
        $tenantUserDepartmentList = [];
        foreach ($param['department_id'] as $departmentId) {
            if (in_array($departmentId, $existDepartmentIdList)) {
                unset($needDeleteTenantUserDepartmentIdList[$departmentId]);
                continue;
            }
            $tenantUserDepartmentList[] = [
                'tenant_user_id' => $existUser['id'],
                'department_id' => $departmentId,
                'created' => time(),
                'created_by' => fill_created_by(),
            ];
        }
        $resData = [];
        model(TenantUserDepartmentModel::class)->startTrans();
        try {
            if (!empty($tenantUserDepartmentList)) {
                $resData['added'] = model(TenantUserDepartmentModel::class)->addAll($tenantUserDepartmentList);
            }
            if (!empty($needDeleteTenantUserDepartmentIdList)) {
                $resData['deleted'] = model(TenantUserDepartmentModel::class)->where(['id' => ['IN', array_values($needDeleteTenantUserDepartmentIdList)]])->delete();
                try {
                    // 从需要删除的部门删除
                    TenantService::getInstance()->deleteUserFromDepartmentChat($param['user_id'], array_keys($needDeleteTenantUserDepartmentIdList));
                } catch (\Throwable $e) {
                    trace(format_exception_info($e), 'ERR');
                }
            }
            model(TenantUserDepartmentModel::class)->commit();
        } catch (\Throwable $e) {
            model(TenantUserDepartmentModel::class)->rollback();
            throw $e;
        }
        // 自动加入公司和部门群聊
        try {
            TenantService::getInstance()->autoAddCompanyChat($param['tenant_id'], $param['department_id'], $param['user_id']);
        } catch (\Throwable $e) {
            trace("auto add department chat got exception", "ERR");
            trace(format_exception_info($e), 'ERR');
        }
        Cache::rm('tenant_user_tree' . $param['tenant_id']);
        return $resData;
    }

    /**
     * 查询租户成员的部门和角色信息
     * @param $tenantUserIdList
     * @return array
     */
    public function getTenantUserListDepartmentRole($tenantUserIdList)
    {
        $tenantUserDepartmentList = model(TenantUserDepartmentModel::class)->alias('tud')
            ->join('department on department.id = tud.department_id')
            ->where(['tud.tenant_user_id' => ['IN', implode(',', $tenantUserIdList)]])
            ->field('tud.tenant_user_id,department.*')
            ->select();
        $tenantUserDepartmentList = array_group_by($tenantUserDepartmentList, 'tenant_user_id');
        $tenantUserRoleList = model(TenantUserRoleModel::class)->alias('tur')
            ->join('role on role.id = tur.role_id')
            ->where(['tur.tenant_user_id' => ['IN', implode(',', $tenantUserIdList)]])
            ->field('tur.tenant_user_id,role.*')
            ->select();
        $tenantUserRoleList = array_group_by($tenantUserRoleList, 'tenant_user_id');
        $res = array_fill_keys($tenantUserIdList, null);
        foreach ($res as $tenantUserId => &$resItem) {
            $resItem = [];
            $resItem['department_info'] = $tenantUserDepartmentList[$tenantUserId] ?? [];
            $resItem['role_info'] = $tenantUserRoleList[$tenantUserId] ?? [];
        }
        return $res;
    }

    /**
     * 租户成员标记离职
     * @param $filter
     * @return array
     * @throws \Throwable
     */
    public function depart($filter)
    {
        $tenantUser = model(TenantUserModel::class)->where($filter)->find();
        if (empty($tenantUser)) {
            throw new LogicException('tenantUser not found', ErrorCode::TENANT_USER_NOT_FOUND);
        }
        $firstNotActiveTenantUser = null;
        if ($tenantUser['status'] === TenantUserModel::STATUS_UNEMPLOYED) {
            throw new LogicException('tenantUser is already unemployed', ErrorCode::TENANT_USER_ALREADY_UNEMPLOYED);
        } elseif ($tenantUser['status'] === TenantUserModel::STATUS_ACTIVE) {
            $firstNotActiveTenantUser = model(TenantUserModel::class)->where(['user_id' => $tenantUser['user_id'], 'status' => TenantUserModel::STATUS_INVALID])->find();
        }
        /**
         * 1. 标记用户离职
         * 2. 退出与公司相关的群聊
         * 3. 退出项目成员 todo
         * 4. 未完成任务交接(审核,任务制作人,任务负责人,任务分配制片,订单负责人) todo
         */

        $chatUserIdList = model(ChatModel::class)
            ->join('chat_user on chat_user.chat_global_id = chat.global_id')
            ->where([
                'chat_user.user_id' => $tenantUser['user_id'],
                'chat_user.is_leave' => 'no',
                'chat.from_tenant_id' => $tenantUser['tenant_id'],
                'chat.link_type' => ['IN', ['tenant', 'department', 'project', 'episode', 'entity', 'order', 'settlement',]],
            ])
            ->field('chat_user.id')
            ->column('id');
        $res = [];
        model(ChatUserModel::class)->startTrans();
        try {
            if (!empty($chatUserIdList)) {
                $res['chat_user_updated'] = model(ChatUserModel::class)->where(['id' => ['IN', $chatUserIdList]])->setField("is_leave", "yes");
            }
            $res['tenant_user_updated'] = model(TenantUserModel::class)->save(['id' => $tenantUser['id'], 'status' => TenantUserModel::STATUS_UNEMPLOYED]);
            if (!empty($firstNotActiveTenantUser)) {
                $res['active_tenant_user'] = model(TenantUserModel::class)->execute("update tenant_user set status = 'active' where id  = {$firstNotActiveTenantUser['id']}");
            }
            // 任务系统处理
            teamones_request('teamones-saas', 'tenant/remove_tenant_user', ['param' => [
                'tenant_id' => $tenantUser['tenant_id'],
                'user_id' => $tenantUser['user_id'],
            ]]);
            model(ChatUserModel::class)->commit();
        } catch (\Throwable $e) {
            model(ChatUserModel::class)->rollback();
            throw $e;
        }
        Cache::rm('tenant_user_tree' . $tenantUser['tenant_id']);
        return $res;
    }

    /**
     * 移除离职状态
     * @param $filter
     * @return array
     * @throws \Throwable
     */
    public function entry($filter)
    {
        $tenantUser = model(TenantUserModel::class)->where($filter)->find();
        if (empty($tenantUser)) {
            throw new LogicException('tenantUser not found', ErrorCode::TENANT_USER_NOT_FOUND);
        }
        if ($tenantUser['status'] !== TenantUserModel::STATUS_UNEMPLOYED) {
            throw new LogicException('tenantUser is not unemployed', ErrorCode::TENANT_USER_IS_NOT_UNEMPLOYED);
        }
        /**
         * 1. 标记用户没有离职
         * 2. 重新加入公司/部门群聊
         */
        $chatUserIdList = model(ChatModel::class)
            ->join('chat_user on chat_user.chat_global_id = chat.global_id')
            ->where([
                'chat_user.user_id' => $tenantUser['user_id'],
                'chat_user.is_leave' => 'yes',
                'chat.from_tenant_id' => $tenantUser['tenant_id'],
            ])
            ->field('chat_user.id')
            ->column('id');
        //
        $activeTenantUser = model(TenantUserModel::class)->where(['user_id' => $tenantUser['user_id'], 'status' => TenantUserModel::STATUS_ACTIVE])->find();
        $res = [];
        model(ChatUserModel::class)->startTrans();
        try {
            if (!empty($chatUserIdList)) {
                $res['chat_user_updated'] = model(ChatUserModel::class)->where(['id' => ['IN', $chatUserIdList]])->setField("is_leave", "no");
            }
            $res['tenant_user_updated'] = model(TenantUserModel::class)->save(['id' => $tenantUser['id'], 'status' => empty($activeTenantUser) ? TenantUserModel::STATUS_ACTIVE : TenantUserModel::STATUS_INVALID]);
            model(ChatUserModel::class)->commit();
        } catch (\Throwable $e) {
            model(ChatUserModel::class)->rollback();
            throw $e;
        }
        // 自动加入公司和部门群聊
        try {
            $departmentIdList = model(TenantUserDepartmentModel::class)
                ->where(['tenant_user_id' => $tenantUser['id']])
                ->field('department_id')
                ->column('department_id');
            TenantService::getInstance()->autoAddCompanyChat($tenantUser['tenant_id'], $departmentIdList, $tenantUser['user_id']);
        } catch (\Throwable $e) {
            trace("auto add department chat got exception", "ERR");
            trace(format_exception_info($e), 'ERR');
        }
        Cache::rm('tenant_user_tree' . $tenantUser['tenant_id']);
        return $res;
    }
}
